//
// Created by Yun Zeng on 2018/4/14.
// 温湿度计 SHT20
//

#include "platform_ht.h"
#include "master.h"

#include <linux/i2c.h>
#include <linux/delay.h>

#define SHT20_I2C_ADDRESS			0x40

#define SHT20_TRIGGER_TEMPERATURE_MEAS	0xF3
#define SHT20_TRIGGER_HUMIDITY_MEAS		0xF5
#define SHT20_WRITE_USER_REG			0xE6
#define SHT20_READ_USER_REG			    0xE7

#define SHT20_MEAS_TIME_HUMIDITY		29
#define SHT20_MEAS_TIME_TEMPERATURE		85
#define SHT20_STATUS_BITS_MASK			0x03
#define SHT20_RESULT_TYPE			    0x02
#define SHT20_TEMPERATURE_RESULT		0x00
#define SHT20_HUMIDITY_RESULT			0x02

// I2C 驱动设备信息
struct i2c_adapter* sht20_dev;
struct i2c_client* sht20_client;

static struct i2c_board_info __initdata board_info =  {
    .type = "sht20", .addr = SHT20_I2C_ADDRESS,
};

static ht_recv_callback recv_callback = NULL;

// 读取温度
static int32_t sht20_read_temperature(int16_t *temperature) {
    int32_t result = i2c_smbus_write_byte(sht20_client, SHT20_TRIGGER_TEMPERATURE_MEAS);
    if (result < 0) {
        return result;
    }

    msleep(SHT20_MEAS_TIME_TEMPERATURE);
    result = i2c_master_recv(sht20_client, (unsigned char*)temperature, sizeof(*temperature));
    if (result < 0) {
        return result;
    }

    *temperature = be16_to_cpu(*temperature);
    if ((*temperature & SHT20_RESULT_TYPE) != SHT20_TEMPERATURE_RESULT) {
        result = -ERESTARTSYS;
        return result;
    }

    *temperature = *temperature & ~SHT20_STATUS_BITS_MASK;
    *temperature = -4685 + ((17572 * *temperature) >> 16);
    *temperature = cpu_to_be16(*temperature);

    return result;
}

// 读取湿度
static int32_t sht20_read_humidity(uint16_t *humidity) {
    int32_t result = i2c_smbus_write_byte(sht20_client, SHT20_TRIGGER_HUMIDITY_MEAS);
    if (result < 0) {
        return result;
    }

    msleep(SHT20_MEAS_TIME_HUMIDITY);
    result = i2c_master_recv(sht20_client, (unsigned char*)humidity, 2);
    if (result < 0) {
        return result;
    }

    *humidity = be16_to_cpu(*humidity);
    if ((*humidity & SHT20_RESULT_TYPE) != SHT20_HUMIDITY_RESULT) {
        result = -ERESTARTSYS;
        return result;
    }

    *humidity = *humidity & ~0x03;
    *humidity = -600 + ((*humidity * 12500) >> 16);
    *humidity = cpu_to_be16(*humidity);
    return result;
}

int32_t platform_ht_write(uint8_t *data, uint16_t len) {
    platform_ht_data_typedef ht;
    if (sht20_read_temperature(&ht.temperature) < 0) {
        return -1;
    }

    if (sht20_read_humidity(&ht.humidity) < 0) {
        return -2;
    }

    if (recv_callback != NULL) {
        recv_callback(&ht);
    }
    return 0;
}

// 温湿度计设备初始化
int platform_ht_init(ht_recv_callback callback) {
    recv_callback = callback;
    sht20_dev = i2c_get_adapter(0);
    printk(MASTER_DEV_NAME ": sht20_dev: %08x\n", (int)sht20_dev);
    sht20_client = i2c_new_device(sht20_dev, &board_info);
    return 0;
}


int platform_ht_exit(void) {
    if (sht20_client != NULL) {
        i2c_unregister_device(sht20_client);
    }
    return 0;
}


